package com.exam.student.service.serviceimpl;

import com.exam.anno.MyLog;
import com.exam.constant.JwtClaimsConstant;
import com.exam.constant.MessageConstant;
import com.exam.entity.*;
import com.exam.entity.dto.*;
import com.exam.entity.vo.MessageVo;
import com.exam.entity.vo.ReplayVo;
import com.exam.properties.JwtProperties;
import com.exam.student.mapper.PageMapper;
import com.exam.student.mapper.UserMapper;
import com.exam.student.service.LoginService;
import com.exam.util.AliOssUtil;
import com.exam.util.JwtUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PageMapper pageMapper;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AliOssUtil aliOssUtil;

    /**
     * 用户登录并判断身份
     *
     * @param login
     * @return
     */
    @Transactional
    @Override
    public ApiResult login(Login login) {

        ApiResult apiResult = new ApiResult();
        StudentDto student = userMapper.selectStudent(login);
        TeacherDto teacher = userMapper.selectTeacher(login);
        AdminDto admin = userMapper.selectAdmin(login);

        Map<String, Object> claims = new HashMap<>();

        if (student != null && teacher == null && admin == null) {
            //登录成功后，生成jwt令牌
            claims.put(JwtClaimsConstant.Student_ID, student.getStudentId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getAdminSecretKey(),
                    jwtProperties.getAdminTtl(),
                    claims);

            if (redisTemplate.opsForValue().get(login.getUsername()) != null) {
                int count = (Integer) redisTemplate.opsForValue().get(login.getUsername());
                apiResult.setCode(205);
                apiResult.setData(student);
                apiResult.setMessage("学生登录成功");
                return apiResult;
            } else {
                student.setToken(token);
                apiResult.setCode(200);
                apiResult.setData(student);
                apiResult.setMessage("学生登录成功");
                redisTemplate.opsForValue().set(login.getUsername(), 1, 1800, TimeUnit.SECONDS);
                return apiResult;
            }

        } else if (teacher != null && student == null && admin == null) {
            //登录成功后，生成jwt令牌
            claims.put(JwtClaimsConstant.Teacher_ID, teacher.getTeacherId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getAdminSecretKey(),
                    jwtProperties.getAdminTtl(),
                    claims);
            teacher.setToken(token);

            apiResult.setCode(200);
            apiResult.setData(teacher);
            apiResult.setMessage("教师登录成功");
        } else if (admin != null && teacher == null && student == null) {
            //登录成功后，生成jwt令牌
            claims.put(JwtClaimsConstant.Admin_ID, admin.getAdminId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getAdminSecretKey(),
                    jwtProperties.getAdminTtl(),
                    claims);
            admin.setToken(token);

            apiResult.setCode(200);
            apiResult.setData(admin);
            apiResult.setMessage("超级管理员登录成功");
        } else {
            apiResult.setCode(404);
            apiResult.setMessage(MessageConstant.LOGIN_ERROR);
        }

        return apiResult;

    }

    /**
     * 注册
     *
     * @param registerDto
     * @return
     */
    @Transactional
    @Override
    public ApiResult register(RegisterDto registerDto) {

        ApiResult apiResult = new ApiResult();
        if (Objects.equals(registerDto.getSex(), "1")) {
            registerDto.setSex("男");
        } else {
            registerDto.setSex("女");
        }

        // 插入操作
        if (registerDto.getStudentName() != null) {
            // 角色类型转换
            registerDto.setRole("2");

            int count = userMapper.registerStudent(registerDto);
            // 插入之后数据回显
            if (count > 0) {
                apiResult.setCode(200);
                apiResult.setMessage("学生注册成功");
                apiResult.setData(userMapper.findStudentById(registerDto.getStudentId()));
            }
        } else {
            if (Objects.equals(registerDto.getInvitationCode(), "zhui2023")) {
                registerDto.setRole("1");
                int count = userMapper.registerTeacher(registerDto);
                // 插入之后数据回显
                if (count > 0) {
                    apiResult.setCode(200);
                    apiResult.setMessage("教师注册成功");
                    apiResult.setData(userMapper.findTeacherById(registerDto.getTeacherId()));
                }
            } else {
                apiResult.setCode(507);
                apiResult.setMessage("教师邀请码错误，请联系管理员");
            }
        }

        return apiResult;
    }

    /**
     * 找回密码
     *
     * @param forgotDto
     * @return
     */
    @Transactional
    @Override
    public ApiResult forgotPwd(ForgotDto forgotDto) {

        ApiResult apiResult = new ApiResult();
        if (forgotDto.getStudentName() != null) {
            // 学生找回密码操作
            Student student = userMapper.forgotStudentPwd(forgotDto);

            if (student != null) {
                apiResult.setCode(200);
                apiResult.setMessage("学生密码找回成功");
                apiResult.setData(student);
            } else {
                apiResult.setCode(507);
                apiResult.setMessage("账号不存在，请自行核实");
            }
        } else if (forgotDto.getTeacherName() != null) {
            // 教师找回密码操作
            Teacher teacher = userMapper.forgotTeacherPwd(forgotDto);

            if (teacher != null) {
                apiResult.setCode(200);
                apiResult.setMessage("教师密码找回成功");
                apiResult.setData(teacher);
            } else {
                apiResult.setCode(507);
                apiResult.setMessage("账号不存在，请自行核实");
            }
        } else {
            // 找回密码失败，抛出异常
            // TODO 找回密码失败，抛出异常 (全局异常捕获)
            System.out.println("找回密码失败，抛出异常");
        }

        return apiResult;
    }

    /**
     * 将头像存储在DB
     *
     * @param avatar
     * @return
     */
    @Override
    public ApiResult insertAvatar(Avatar avatar) {

        LocalDateTime localDateTime = LocalDateTime.now();
        avatar.setCreatedAt(new Date());
        int count = 0;
        if (avatar.getAvatarPath() != null) count = pageMapper.insertAvatar(avatar);
        ApiResult apiResult = new ApiResult();
        if (count > 0) {
            apiResult.setCode(200);
            apiResult.setMessage("查询成功");
        } else {
            apiResult.setCode(506);
            apiResult.setMessage("查询失败");
        }
        return apiResult;
    }

    /**
     * 进入页面根据id查找头像信息
     *
     * @param userId
     * @return
     */
    @Override
    public ApiResult findByIdAvatars(Long userId) {

        List<Avatar> avatarList = userMapper.findByIdAvatars(userId);
        ApiResult apiResult = new ApiResult();
        Avatar avatar = null;
        if (avatarList.size() != 0) {
            avatar = avatarList.get(avatarList.size() - 1);
//            System.out.println(avatar);
            apiResult.setCode(200);
            apiResult.setMessage("查询成功");
            apiResult.setData(avatar);
        } else {
            apiResult.setCode(506);
            apiResult.setMessage("查询失败");
        }
        return apiResult;
    }

    /**
     * 删除oss里面图片
     *
     * @param filePath
     * @return
     */
    @Override
    public ApiResult deleteAvatar(String filePath) {

        ApiResult apiResult = new ApiResult();

        if (filePath != null && filePath != "") {
            int count = userMapper.deleteAvatar(filePath);

            if (count > 0) {
                try {
                    // 删除指定图片对象
                    int lastIndex = filePath.lastIndexOf("/");
                    String result = filePath.substring(lastIndex + 1);
//                    System.out.println(result);
                    aliOssUtil.deleteObject(result);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                apiResult.setCode(200);
                apiResult.setData(filePath);
                apiResult.setMessage("删除成功");
            } else {
                apiResult.setCode(506);
                apiResult.setData(filePath);
                apiResult.setMessage("删除失败");
            }
        } else {
            apiResult.setCode(406);
            apiResult.setData(filePath);
            apiResult.setMessage("删除失败");
        }

        return apiResult;
    }

    /**
     * 退出登录
     *
     * @param exitForm
     * @return
     */
    @Transactional
    @Override
    public ApiResult exit(ExitForm exitForm) {
        ApiResult apiResult = new ApiResult();

        if (redisTemplate.opsForValue().get(exitForm.getUserId()) != null) {
            redisTemplate.delete(exitForm.getUserId());
            apiResult.setCode(200);
            apiResult.setMessage("退出成功");
            return apiResult;
        } else {
            apiResult.setCode(506);
            apiResult.setMessage("退出失败");
            return apiResult;
        }
    }

    /**
     * 登录信息写到缓存
     *
     * @param userId
     * @return
     */
    @Override
    public ApiResult findByIdLiveCount(Long userId) {

        ApiResult apiResult = new ApiResult();
        String strUserId = String.valueOf(userId);
        Integer count = (Integer) redisTemplate.opsForValue().get(strUserId);
//        System.out.println(apiResult);

        if (count != null) {

            apiResult.setCode(205);
            apiResult.setMessage("查询成功");
            redisTemplate.delete(strUserId);
            redisTemplate.opsForValue().set(strUserId, 2, 1800, TimeUnit.SECONDS);
            return apiResult;

        } else {
            apiResult.setCode(404);
            apiResult.setMessage("查询失败");
            return apiResult;
        }


    }

    /**
     * 分页
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public ApiResult examSelectPage(Integer pageNum, Integer pageSize) {

        Page<ExamManage> page = null;
        PageHelper.startPage(pageNum, pageSize);

        page = pageMapper.pageQuery(null);

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("查询成功");
        apiResult.setTotal(page.getTotal());
        apiResult.setSize(page.getPageSize());
        apiResult.setCurrent(pageNum);
        apiResult.setData(page);
        return apiResult;
    }

    /**
     * 试卷查询
     *
     * @param examManage
     * @return
     */
    @Override
    public ApiResult findBySource(ExamManage examManage) {

        List<ExamManage> page = pageMapper.pageQuery(examManage);
        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("查询成功");
        apiResult.setTotal(page.size());
        apiResult.setSize(page.size());
        apiResult.setCurrent(1);
        apiResult.setData(page);
//        System.out.println(apiResult);
        return apiResult;
    }

    /**
     * 查询详细试卷
     *
     * @param paperId
     * @return
     */
    @MyLog
    @Override
    public ApiResult findQuestion(Long paperId) {

        // 查询选择题
        MultiQuestion multiQuestion = new MultiQuestion();
        multiQuestion.setQuestionType(1);
        multiQuestion.setPaperId(paperId);
        List<MultiQuestion> multiQuestionList = pageMapper.findMultiQuestion(multiQuestion);

        // 查询填空题
        FillQuestion fillQuestion = new FillQuestion();
        fillQuestion.setQuestionType(2);
        fillQuestion.setPaperId(paperId);
        List<FillQuestion> fillQuestionList = pageMapper.findFillQuestion(fillQuestion);

        // 查询判断题
        JudgeQuestion judgeQuestion = new JudgeQuestion();
        judgeQuestion.setQuestionType(3);
        judgeQuestion.setPaperId(paperId);
        List<JudgeQuestion> judgeQuestionList = pageMapper.findJudgeQuestion(judgeQuestion);

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("查询成功");
        List<Object> lists = new ArrayList<>();
        lists.add(multiQuestionList);
        lists.add(fillQuestionList);
        lists.add(judgeQuestionList);
        apiResult.setData(lists);

        return apiResult;
    }

    // TODO 这里做插入失败判断

    /**
     * 将学生的分数插入进去
     *
     * @param score
     * @return
     */
    @Override
    public ApiResult insertScore(Score score) {
        int count = pageMapper.insertScore(score);
        if (count > 0) {
            System.out.println("分数插入成功");
        } else {
            System.out.println("插入失败，回滚数据");
        }
        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("查询成功");
        return apiResult;
    }

    /**
     * 查询我的分数
     *
     * @param pageNum
     * @param pageSize
     * @param examCode
     * @return
     */
    @Override
    public ApiResult findMyScore(Integer pageNum, Integer pageSize, Long examCode) {
        Page<Score> page = null;
        PageHelper.startPage(pageNum, pageSize);
        Score score = new Score();
        score.setStudentId(examCode);
        page = pageMapper.findMyScore(score);

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("查询成功");
        apiResult.setTotal(page.getTotal());
        apiResult.setSize(page.getPageSize());
        apiResult.setCurrent(pageNum);
        apiResult.setData(page);

        return apiResult;
    }

    /**
     * 留言消息分页
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public ApiResult findAllMessage(Integer pageNum, Integer pageSize) {

        MessageVo messageVo = new MessageVo();
        messageVo.setPageNum(pageNum);
        messageVo.setPageSize(pageSize);
        List<ReplayVo> allReplay = pageMapper.findAllReplay(null);

        Page<MessageVo> page = null;
        PageHelper.startPage(pageNum, pageSize);

        page = pageMapper.findAllMessage(messageVo);

//        // TODO 需要优化，内存太浪费了
        for (MessageVo message : page) {
            List<ReplayVo> list = new ArrayList<>();
            for (ReplayVo replay : allReplay) {
                if (Objects.equals(replay.getMessageId(), message.getId())) {
                    list.add(replay);
                }
                message.setReplays(list);
            }
        }

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("查询成功");
        apiResult.setTotal(page.getTotal());
        apiResult.setSize(page.getPageSize());
        apiResult.setCurrent(pageNum);
        apiResult.setData(page);

        return apiResult;
    }

    /**
     * 插入留言消息
     *
     * @param messageVo
     * @return
     */
    @Override
    public ApiResult insertMessage(MessageVo messageVo) {

        int count = pageMapper.insertMessage(messageVo);

        if (count > 0) {
            System.out.println("插入成功");
        } else {
            System.out.println("插入失败");
        }

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("插入成功");
        return apiResult;
    }

    /**
     * 插入评论消息
     *
     * @param replayVo
     * @return
     */
    @Override
    public ApiResult insertReplay(ReplayVo replayVo) {

        int count = pageMapper.insertReplay(replayVo);

        if (count > 0) {
            System.out.println("插入成功");
        } else {
            System.out.println("插入失败");
        }

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("插入成功");
        return apiResult;
    }

    /**
     * 删除评论消息
     *
     * @param replayVo
     * @return
     */
    @Override
    public ApiResult replayDelete(ReplayVo replayVo) {

        int count = pageMapper.replayDelete(replayVo);

        if (count > 0) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("删除成功");
        return apiResult;
    }

    /**
     * 删除留言消息
     *
     * @param messageVo
     * @return
     */
    @Transactional
    @Override
    public ApiResult deleteMessage(MessageVo messageVo) {

        // 删除留言
        int countMessage = pageMapper.deleteMessage(messageVo);
        // 循环删除留言下的评论
        ReplayVo replayVo = new ReplayVo();
        replayVo.setMessageId(messageVo.getId());
        int countReplay = pageMapper.replayDelete(replayVo);

        if (countMessage > 0 && countReplay > 0) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("删除成功");
        return apiResult;
    }

    /**
     * 学生修改密码
     *
     * @param updatePwdDto
     * @return
     */
    @Override
    public ApiResult updatePwdDto(RegisterDto updatePwdDto) {

        int updateCount = pageMapper.updatePwdDto(updatePwdDto);

        if (updateCount > 0) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }

        ApiResult apiResult = new ApiResult();
        apiResult.setCode(200);
        apiResult.setMessage("修改成功");
        return apiResult;

    }


}



